<?php
declare(strict_types=1);

namespace App\Service;

use App\Exception\BusinessException;
use App\Http\Common\ResultCode;
use Common\Common;
use Overtrue\EasySms\EasySms;
use Overtrue\EasySms\PhoneNumber;
use Overtrue\EasySms\Strategies\OrderStrategy;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;

class SmsService
{
    public function send(PhoneNumber $phone, array $msg): bool
    {
        $res = Common::getConfigByGroup('sms');
        $res = array_map(function ($item) {return $item['value'];}, $res);
        $gateways = [
            'errorlog' => [
                'file' => BASE_PATH . '/runtime/logs/sms.log',
            ],
        ];
        $data['data'] = $msg;
        if ($res['sms_mode'] == 1) {
            $gateways = array_merge($gateways, [
                'qcloud' => [
                    'sdk_app_id' => $res['qqsms_app_id'],
                    'secret_id' => $res['qqsms_secret_id'],
                    'secret_key' => $res['qqsms_secret_key'],
                    'sign_name' => $res['qqsms_sign_name'],
                ],
            ]);
            $data['template'] = $res['qqsms_uni_template'];
        }
        if ($res['sms_mode'] == 2) {
            $gateways = array_merge($gateways, [
                'qcloud' => [
                    'sdk_app_id' => $res['qqsms_app_id'],
                    'secret_id' => $res['qqsms_secret_id'],
                    'secret_key' => $res['qqsms_secret_key'],
                    'sign_name' => $res['qqsms_sign_name'],
                ],
            ]);
            $data['template'] = $res['qqsms_uni_template'];
        }
        $config = [
            'timeout' => 5.0,
            'default' => [
                'strategy' => OrderStrategy::class,
                'gateways' => ['qcloud'],
            ],
            'gateways' => $gateways,
        ];
        try {
            $easySms = new EasySms($config);
            $easySms->send($phone, $data);
            return true;
        } catch (\Exception $exception) {
            throw new BusinessException(ResultCode::FAIL, '验证码发送失败:' . $exception->getMessage());
        }
    }

    /**
     * 通用验证码
     * @param string|int $phone
     * @param string|int $code
     * @return bool
     * @throws ContainerExceptionInterface
     * @throws NotFoundExceptionInterface
     * @throws \RedisException
     */
    public function sendUniversalCode(string|int $phone, string|int $code = 86, string $key = 'default'): bool
    {
//        if (env('APP_ENV') == 'dev') return true;
        $k = 'sms:' . $key . ':' . $code . $phone;
        $redis = Common::redis();
        $vcode = $redis->get($k);
        if (!$vcode) $vcode = random_int(1000, 9999);
        $ttl = 610;
        $s = 0;
        $t = (int)$redis->ttl($k);
        if (($ttl - $t) > 120) {
            $s = 1;
        }
        if ($s) {
            $redis->setnx($k, $vcode);
            $redis->expire($k, $ttl);
            $ph = new PhoneNumber((int)$phone, (string)$code);
            return $this->send($ph, [$vcode]);
        }
        return true;
    }

    /**
     * 短信验证
     * @param string|int $phone
     * @param string|int $vcode
     * @param bool $clean
     * @param string $key
     * @return bool
     * @throws ContainerExceptionInterface
     * @throws NotFoundExceptionInterface
     * @throws \RedisException
     */
    public function validate(string|int $phone, string|int $vcode, string|int $code = 86, string $key = 'default', bool $clean = true, string $debug = ''): bool
    {
//        if (config('app_env') == 'dev') return true;
        $redis = Common::redis();
        $k = 'sms:' . $key . ':' . $code . $phone;
        $c = $redis->get($k);
        /*if ($debug) \Hyperf\Coroutine\go(function () use ($k, $vcode, $c, $clean, $debug) {
            try {
                sys_notify($debug . '|' . $k . '=>clean=' . ($clean ? 1 : 0) . '|vcode=>' . $vcode . '=' . $c);
            } catch (\Throwable) {}
        });*/
        if ($c && $c == $vcode) {
            if ($clean) $redis->del($k);
            return true;
        }
        throw new BusinessException(ResultCode::FORBIDDEN, '验证码错误');
    }
}